#include "Matrix2.h"

Matrix2::Matrix2()
{	
	this->_elements.e11 = 1.0;
	this->_elements.e12 = 0.0;
	this->_elements.e13 = 0.0;
	this->_elements.e21 = 0.0;
	this->_elements.e22 = 1.0;
	this->_elements.e23 = 0.0;
	this->_elements.e31 = 0.0;
	this->_elements.e32 = 0.0;
	this->_elements.e33 = 1.0;
}

Matrix2::Matrix2(const Matrix2 &mat)
{	
	this->_elements.e11 = mat._elements.e11;
	this->_elements.e12 = mat._elements.e12;
	this->_elements.e13 = mat._elements.e13;
	this->_elements.e21 = mat._elements.e21;
	this->_elements.e22 = mat._elements.e22;
	this->_elements.e23 = mat._elements.e23;
	this->_elements.e31 = mat._elements.e31;
	this->_elements.e32 = mat._elements.e32;
	this->_elements.e33 = mat._elements.e33;
}


Matrix2::Matrix2( float e11,float e12, float e21,float e22 )
{
	this->_elements.e11 = e11;
	this->_elements.e12 = e12;
	this->_elements.e13 = 0.0;
	this->_elements.e21 = e21;
	this->_elements.e22 = e22;
	this->_elements.e23 = 0.0;
	this->_elements.e31 = 0.0;
	this->_elements.e32 = 0.0;
	this->_elements.e33 = 1.0;
}

Matrix2::Matrix2( float e11,float e12,float e13, float e21,float e22, float e23, float e31,float e32, float e33 )
{
	this->_elements.e11 = e11;
	this->_elements.e12 = e12;
	this->_elements.e13 = e13;
	this->_elements.e21 = e21;
	this->_elements.e22 = e22;
	this->_elements.e23 = e23;
	this->_elements.e31 = e31;
	this->_elements.e32 = e32;
	this->_elements.e33 = e33;
}

Matrix2::Matrix2( MatrixElements elements )
{
	this->_elements = elements;
}					

//Getter/Setter
MatrixElements Matrix2::getElements() const
{
	return this->_elements;
}

void Matrix2::setElements( MatrixElements elements)
{
	this->_elements = elements;
}

//Overload Operators
Matrix2 Matrix2::operator * (const Matrix2 &mat2) const
{
	Matrix2 mat(
						this->_elements.e11 * mat2._elements.e11 + this->_elements.e12 * mat2._elements.e21 + this->_elements.e13 * mat2._elements.e31,
						this->_elements.e11 * mat2._elements.e12 + this->_elements.e12 * mat2._elements.e22 + this->_elements.e13 * mat2._elements.e32,
						this->_elements.e11 * mat2._elements.e13 + this->_elements.e12 * mat2._elements.e23 + this->_elements.e13 * mat2._elements.e33,

						this->_elements.e21 * mat2._elements.e11 + this->_elements.e22 * mat2._elements.e21 + this->_elements.e23 * mat2._elements.e31,
						this->_elements.e21 * mat2._elements.e12 + this->_elements.e22 * mat2._elements.e22 + this->_elements.e23 * mat2._elements.e32,
						this->_elements.e21 * mat2._elements.e13 + this->_elements.e22 * mat2._elements.e23 + this->_elements.e23 * mat2._elements.e33,

						this->_elements.e31 * mat2._elements.e11 + this->_elements.e32 * mat2._elements.e21 + this->_elements.e33 * mat2._elements.e31,
						this->_elements.e31 * mat2._elements.e12 + this->_elements.e32 * mat2._elements.e22 + this->_elements.e33 * mat2._elements.e32,
						this->_elements.e31 * mat2._elements.e13 + this->_elements.e32 * mat2._elements.e23 + this->_elements.e33 * mat2._elements.e33
	);
	return mat;
}


Matrix2 Matrix2::operator + (const Matrix2 &mat2) const
{
	Matrix2 mat(  
      this->_elements.e11 + mat2.getElements().e11,
			this->_elements.e12 + mat2.getElements().e12,
			this->_elements.e13 + mat2.getElements().e13,

      this->_elements.e21 + mat2.getElements().e21,
			this->_elements.e22 + mat2.getElements().e22,
			this->_elements.e23 + mat2.getElements().e23,

      this->_elements.e31 + mat2.getElements().e31,
			this->_elements.e32 + mat2.getElements().e32,
			this->_elements.e33 + mat2.getElements().e33
		);
	return mat;
}

Matrix2 Matrix2::operator - (const Matrix2 &mat2) const
{
	Matrix2 mat(  
      this->_elements.e11 - mat2.getElements().e11,
			this->_elements.e12 - mat2.getElements().e12,
			this->_elements.e13 - mat2.getElements().e13,

      this->_elements.e21 - mat2.getElements().e21,
			this->_elements.e22 - mat2.getElements().e22,
			this->_elements.e23 - mat2.getElements().e23,

      this->_elements.e31 - mat2.getElements().e31,
			this->_elements.e32 - mat2.getElements().e32,
			this->_elements.e33 - mat2.getElements().e33
		);
	return mat;
}

Vector2 Matrix2::operator * (const Vector2 &vec) const
{
	Vector2 tmpVec(
						vec.getX() * this->getElements().e11 + vec.getY() * this->getElements().e12 + vec.getW() * this->getElements().e13,
						vec.getX() * this->getElements().e21 + vec.getY() * this->getElements().e22 + vec.getW() * this->getElements().e23,
						vec.getX() * this->getElements().e31 + vec.getY() * this->getElements().e32 + vec.getW() * this->getElements().e33

	);
	return tmpVec;
}

Vector2 Matrix2::MultNormal( Vector2 vec ) const
{
	Vector2 tmpVec(
						vec.getX() * this->getElements().e11 + vec.getY() * this->getElements().e12,
						vec.getX() * this->getElements().e21 + vec.getY() * this->getElements().e22,
						vec.getX() * this->getElements().e31 + vec.getY() * this->getElements().e32
	);
	tmpVec.normalize();
	return tmpVec;
}

Matrix2 Matrix2::operator * (const float& scal) const
{
	Matrix2 tmpMat( 
									scal * this->getElements().e11 , scal * this->getElements().e12, 
									scal * this->getElements().e21 , scal * this->getElements().e22 
	);

	return tmpMat;
}


float Matrix2::getDeterminant() const
{
 return ( this->getElements().e11 * this->getElements().e22 ) - ( this->getElements().e12 * this->getElements().e21 );
}

Matrix2 Matrix2::getInverse() const
{
	// determinante ausrechnen
	float det = getDeterminant();
	if( GeoMath::Abs(det) < GeoMath::EPS )
		throw " |-X- Exception -X-| Determinant is 0, cannot calc the inverse!";

	// inverse der determinante
	det = 1.0/det;

	// matrix elemente vertauschen und e12, e21 mal "-1" nehmen 
	Matrix2 mat(  
				mat.getElements().e22, -mat.getElements().e21, mat.getElements().e13,
				-mat.getElements().e12, mat.getElements().e11, mat.getElements().e23,
				mat.getElements().e31, mat.getElements().e32, mat.getElements().e33
	);

	// matrix mit der determinante multiplizieren
	mat = mat * det;

	return mat;
}

void Matrix2::InverseMatrix()
{
	this->setElements( this->getInverse().getElements() );
}


ostream & operator<< (ostream &o, const Matrix2 &mat)
{
	o 	<< "["<<mat.getElements().e11<<"] ["<<mat.getElements().e12<<"] ["<<mat.getElements().e13<<"]"<<endl
		<< "["<<mat.getElements().e21<<"] ["<<mat.getElements().e22<<"] ["<<mat.getElements().e23<<"]"<<endl
		<< "["<<mat.getElements().e31<<"] ["<<mat.getElements().e32<<"] ["<<mat.getElements().e33<<"]"<<endl;
	return o;
}
